package indigo.mybatis.entity;

import static java.util.Objects.requireNonNull;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Optional;

import org.apache.ibatis.type.JdbcType;

import com.google.common.base.Strings;

public class PropertyMetadata implements Serializable {
	private static final long serialVersionUID = -6628801992434328011L;

	private final String name;
	private final Class<?> type;
	private final String columnName;
	private final JdbcType jdbcType;
	private final boolean insertable;
	private final boolean updatable;
	private final Field field;
	private final Method getter;
	private final Method setter;

	protected PropertyMetadata(Builder builder) {
		this.name = builder.getName();
		this.type = builder.getType();
		this.columnName = builder.getColumnName();
		this.jdbcType = builder.getJdbcType();
		this.insertable = builder.isInsertable();
		this.updatable = builder.isUpdatable();
		this.field = builder.field;
		this.getter = builder.getGetter();
		this.setter = builder.getSetter();
	}

	public String getName() {
		return name;
	}

	public Class<?> getType() {
		return type;
	}

	public String getColumnName() {
		return columnName;
	}

	public JdbcType getJdbcType() {
		return jdbcType;
	}

	public boolean isInsertable() {
		return insertable;
	}

	public boolean isUpdatable() {
		return updatable;
	}

	public Field getField() {
		return field;
	}

	public Method getGetter() {
		return getter;
	}

	public Method getSetter() {
		return setter;
	}

	public static class Builder {
		private String name;
		private Class<?> type;
		private String columnName;
		private JdbcType jdbcType = JdbcType.UNDEFINED;
		private boolean insertable = true;
		private boolean updatable = true;
		private Field field;
		private Method getter;
		private Method setter;

		public PropertyMetadata build() {
			requireNonNull(name, "name cannot be null");
			requireNonNull(type, "type cannot be null");
			requireNonNull(columnName, "columnName cannot be null");
			return new PropertyMetadata(this);
		}

		public void setName(String name) {
			this.name = Strings.emptyToNull(name);
		}

		public void setType(Class<?> type) {
			this.type = type;
		}

		public void setColumnName(String columnName) {
			this.columnName = Strings.emptyToNull(columnName);
		}

		public void setJdbcType(JdbcType jdbcType) {
			this.jdbcType = Optional.ofNullable(jdbcType).orElse(JdbcType.UNDEFINED);
		}

		public void setInsertable(boolean insertable) {
			this.insertable = insertable;
		}

		public void setUpdatable(boolean updatable) {
			this.updatable = updatable;
		}

		public void setField(Field field) {
			this.field = field;
		}

		public void setGetter(Method getter) {
			this.getter = getter;
		}

		public void setSetter(Method setter) {
			this.setter = setter;
		}

		public String getName() {
			return name;
		}

		public Class<?> getType() {
			return type;
		}

		public String getColumnName() {
			return columnName;
		}

		public JdbcType getJdbcType() {
			return jdbcType;
		}

		public boolean isInsertable() {
			return insertable;
		}

		public boolean isUpdatable() {
			return updatable;
		}

		public Field getField() {
			return field;
		}

		public Method getGetter() {
			return getter;
		}

		public Method getSetter() {
			return setter;
		}
	}
}
